<?php
declare(strict_types=1);

namespace Jylnnlee\HyperfGenFullstack\Command;

use Hyperf\Command\Annotation\Command;
use Hyperf\Command\Command as HyperfCommand;
use Hyperf\DB\DB;
use Symfony\Component\Console\Input\InputArgument;
use Util\HyperfGenFullstack\Generator\MigrationGenerator;
use Util\HyperfGenFullstack\Helper\TypeMapper;
use Psr\Container\ContainerInterface;

#[Command]
class FullModelGenerateCommand extends HyperfCommand
{
    protected ?string $name = 'make:full-model';

    public function __construct(protected ContainerInterface $container)
    {
        parent::__construct();
    }

    public function configure(): void
    {
        $this->setDescription('生成带注释、类型映射、JSON 自动 cast 的 Model + Migration');
        $this->addArgument('table', InputArgument::REQUIRED, '要操作的数据表名');
        $this->addOption('soft-delete', 'sd', InputArgument::OPTIONAL, '是否启用软删除字段 deleted_at');
        $this->addOption('from-database', 'fd', InputArgument::OPTIONAL, '是否从数据库反向生成');
    }

    public function handle(): void
    {
        $table = $this->input->getArgument('table');
        $withSoftDelete = $this->input->getOption('soft-delete');
        $fromDatabase = $this->input->getOption('from-database');

        if ($fromDatabase) {
            if (!preg_match('/^[a-zA-Z0-9_]+$/', $table)) {
                $this->line('❌ 表名包含非法字符，请使用合法标识符。', 'error');
                return;
            }

            $columns = Db::query("SHOW FULL COLUMNS FROM `$table`");
            $fields = [];
            foreach ($columns as $col) {
                $fields[] = [
                    'name' => $col->Field,
                    'type' => $this->extractColumnType($col->Type),
                    'default' => $col->Default,
                    'nullable' => $col->Null === 'YES',
                    'comment' => $col->Comment,
                ];
            }

            $modelContent = $this->buildModelFromColumns($table, $fields, $withSoftDelete);
            $modelPath = "app/Model/" . ucfirst($table) . ".php";

            // 创建目录
            $dir = dirname($modelPath);
            if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
                $this->line("❌ 无法创建目录：$dir", 'error');
                return;
            }

            if (file_exists($modelPath)) {
                $this->line("⚠️ 文件已存在：{$modelPath}，是否覆盖？[y/N]", 'comment');
                $answer = strtolower(trim(fgets(STDIN)));
                if ($answer !== 'y') {
                    $this->line("跳过写入：$modelPath", 'info');
                    return;
                }
            }

            if (file_put_contents($modelPath, $modelContent) === false) {
                $this->line("❌ 写入文件失败：$modelPath", 'error');
                return;
            }

            MigrationGenerator::generate($table, $fields, $withSoftDelete);
        }

        $this->line("✅ 已成功生成 Model 和 Migration！", 'info');
    }

    protected function extractColumnType(string $rawType): string
    {
        $type = strtolower(explode('(', $rawType)[0]);
        return match ($type) {
            'tinyint' => 'tinyint',
            'smallint' => 'smallint',
            'mediumint' => 'mediumint',
            'int', 'integer' => 'int',
            'bigint' => 'bigint',
            'varchar' => 'varchar',
            'char' => 'char',
            'text' => 'text',
            'datetime' => 'datetime',
            'json' => 'json',
            default => 'string'
        };
    }

    protected function buildModelFromColumns(string $table, array $columns, bool $withSoftDelete): string
    {
        $properties = '';
        $casts = [];

        foreach ($columns as $col) {
            $type = TypeMapper::getCastType($col['type']);
            $casts[$col['name']] = $type;
            $phpType = match ($type) {
                'datetime' => '\Carbon\Carbon ',
                'boolean' => 'bool ',
                'array' => 'array ',
                default => 'mixed '
            };
            $properties .= " * @property $phpType\$$col[name]\n";
        }

        $uses = '';
        if ($withSoftDelete) {
            $uses = "use Hyperf\\Database\\Model\\SoftDeletes;\n";
            $casts['deleted_at'] = 'datetime';
            $properties .= " * @property \Carbon\Carbon|null \$deleted_at\n";
        }

        $castLines = [];
        foreach ($casts as $name => $castType) {
            $castLines[] = "        '$name' => '$castType'";
        }
        $castStr = implode(",\n", $castLines);

        return <<<PHP
<?php

declare(strict_types=1);

namespace App\Model;

$uses

/**
 * Model for table `$table`
 *
$properties
 */
class {$this->toPascalCase($table)} extends Model
{
    use SoftDeletes;

    protected ?string \$table = '$table';
    protected array \$casts = [
$castStr
    ];
}
PHP;
    }

    protected function toPascalCase(string $str): string
    {
        return str_replace(' ', '', ucwords(implode(' ', explode('_', $str))));
    }
}
